package com.lam.common.components.captcha.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.anji.captcha.model.vo.CaptchaVO;
import com.lam.common.components.captcha.enums.CaptchaCategoryEnum;
import com.lam.common.components.captcha.enums.CaptchaTypeEnum;
import com.lam.common.components.captcha.instances.kaptcha.KaptchaKit;
import com.lam.common.components.captcha.instances.simple.SimpleCaptcha;
import com.lam.common.components.captcha.model.CaptchaEntry;
import com.lam.common.components.captcha.model.CaptchaInfo;
import com.lam.common.components.captcha.service.CaptchaService;
import com.lam.common.components.captcha.vo.CodeCaptchaVo;
import com.lam.common.components.parameter.ParameterConfigUtil;
import com.lam.common.components.redis.RedisUtil;
import com.lam.common.utils.JsonUtil;
import com.lam.common.utils.RandomUtil;
import com.lam.common.utils.StringUtils;
import com.lam.common.utils.uuid.IdUtils;
import com.lam.common.validate.ValidateUtil;

@Service("sysCaptchaService")
public class CaptchaServiceImpl implements CaptchaService {
	
	/** 验证码 redis key, captcha:code:{username}:{uuid} */
	private static final String CODE_KEY_FORMAT = "captcha:code:%s:%s";
	
	@Autowired
	private KaptchaKit kaptchaKit;
	@Autowired
    private com.anji.captcha.service.CaptchaService anjiCaptchaService;
	
	@Override
	public CaptchaTypeEnum getCaptchaType(CaptchaCategoryEnum captchaCategory) {
		
		String typeScale = ParameterConfigUtil.getValue("captcha.type.scale");
		String defaultType = ParameterConfigUtil.getValue("captcha.type.default", CaptchaTypeEnum.MATH.getName());
		if(StringUtils.isBlank(typeScale)) {
			return CaptchaTypeEnum.value(defaultType);
		}
		
		Map<String, Object> typeScaleMap = JsonUtil.parseJSON(typeScale);
		if(captchaCategory == null) {
			return CaptchaTypeEnum.value(RandomUtil.genByScale(typeScaleMap, defaultType));
		}
		
		Map<String, Object> typeScaleMapNew = new HashMap<>();
		CaptchaTypeEnum type;
		for (Entry<String, Object> entry : typeScaleMap.entrySet()) {
			type = CaptchaTypeEnum.value(entry.getKey());
			if (type != null && captchaCategory == type.getCategory()) {
				typeScaleMapNew.put(entry.getKey(), entry.getValue());
			}
		}
		return CaptchaTypeEnum.value(RandomUtil.genByScale(typeScaleMapNew, defaultType));
	}
	
	@Override
	public CaptchaInfo genCode(String username) {
		
		CaptchaTypeEnum captchaType = getCaptchaType(CaptchaCategoryEnum.CODE);
		CaptchaEntry captchaEntry;
		switch (captchaType) {
		case MATH: 
		case CHAR: captchaEntry = kaptchaKit.genCode(captchaType); break;
		default:
			captchaEntry = SimpleCaptcha.genCode(); break;
		}
		
		// 保存验证码信息
		String uuid = IdUtils.getUid();
		int time = 60;
		Object imgData = captchaEntry.getImgData();
		captchaEntry.setImgData(null);
		RedisUtil.set(String.format(CODE_KEY_FORMAT, username, uuid), captchaEntry, 60);
		
		return new CaptchaInfo(uuid, imgData, time);
	}
	
	@Override
	public boolean checkCode(String username, String category, Object codeData) {
		
		Boolean open = ParameterConfigUtil.getBoolean("captcha.open", true);
		if(!open) {
			return true;
		}
		
		CaptchaCategoryEnum captchaCategory = CaptchaCategoryEnum.value(category);
		ValidateUtil.validRequired(captchaCategory, "验证码类别不能为空！");
		
		if(captchaCategory == CaptchaCategoryEnum.PICTURE) {
			CaptchaVO data = JsonUtil.toJavaObject(codeData, CaptchaVO.class);
			return anjiCaptchaService.verification(data).isSuccess();
		}
		
		CodeCaptchaVo codeInfo = JsonUtil.toJavaObject(codeData, CodeCaptchaVo.class);
		ValidateUtil.validRequired(codeInfo, "验证码不能为空！");
		ValidateUtil.validRequired(codeInfo.getCode(), "验证码不能为空！");
		ValidateUtil.validRequired(codeInfo.getUuid(), "uuid不能为空！");
		
		String key = String.format(CODE_KEY_FORMAT, username, codeInfo.getUuid());
		CaptchaEntry captchaEntry = (CaptchaEntry)RedisUtil.get(key);
		ValidateUtil.validRequired(captchaEntry, "验证码已失效，请重新获取！");
		RedisUtil.del(key);
		CaptchaTypeEnum captchaType = CaptchaTypeEnum.value(captchaEntry.getCaptchaType());
		switch (captchaType) {
		case MATH: 
		case CHAR: return kaptchaKit.checkCode(captchaEntry.getTextData().toString(), codeInfo.getCode()); 
		default:
			return SimpleCaptcha.checkCode(captchaEntry.getTextData().toString(), codeInfo.getCode()); 
		}
		
	}

}
